#include <stdlib.h>
#include <stdio.h>
#include "myFramework.h"
#include "Burning.h"
#include "Entity/ParticleSystem.h"
#include "Graphics/Effect.h"
#include "Graphics/CGShaderProgram.h"
#include "AntTweakBar.h"
#include "glm/gtc/matrix_transform.hpp"

void Burning::Render2D(double timeElapsed)
{
  __super::Render2D(timeElapsed);
  m_renderer->RenderText(50, 50, "Particle demo");

  TwDraw();
}

void Burning::Render(double timeElapsed)
{
  //Render Scene here
  m_camera->Look();

  glDisable(GL_BLEND);
  m_effect->SelectTechnique("Normal");

  //////////////////////////////////////////////////////////////////////////
  // grid here
  m_effect->SelectPass("pass_plain");
  m_effect->SetShaderParam("ModelView", m_camera->GetMatrixModelView());
  m_effect->SetShaderParam("Projection", m_camera->GetMatrixProjection());
  m_effect->SetShaderParam("DiffuseColor", glm::vec4(1,1,1,1));

  m_rtScrene1->Begin();
  m_renderer->EnableTexture(false);
  m_renderer->Clear(SOFT_BLUE);

  DrawGrid();

  //m_effect->SelectPass();
  m_rtScrene1->End();

  ////////////////////////////////////////////////////////////////////////////
  // scene except particle
  m_effect->SetShaderParam("TexDiffuse", m_texOak);
  m_effect->SelectPass("pass_normal");
  m_rtScrene1->Begin();  

  //m_model->Render(timeElapsed);
  
  m_rtScrene1->End();

  //////////////////////////////////////////////////////////////////////////
  // particle here
  m_emitter->Render(timeElapsed, m_effect, m_rtScrene1);
  
  //m_renderer->Clear(SOFT_BLUE);
  //glDepthMask(GL_FALSE);
  //glEnable(GL_BLEND);
  //glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA );
  //m_renderer->EnableTexture();

  //m_effect->SelectPass("pass_particle");
  //m_effect->SetShaderParam("DiffuseColor", glm::vec4(1.f, 0.2, 0.5f, 1.f));
  //m_effect->SetShaderParam("ModelViewProj", m_camera->GetMatrixViewModelProjection() * m_emitter->GetWorldMatrix());
  //m_effect->SetShaderParam("TexSmoke", m_texDiffuse);
  //m_effect->SetShaderParam("Alpha", 1.f);

  //m_rtScrene1->Begin();

  //m_emitter->Render(timeElapsed);
  //
  //m_rtScrene1->End();
  //glDepthMask(GL_TRUE);
  //glDisable(GL_BLEND);

  //////////////////////////////////////////////////////////////////////////
  // final pass, put everything together
  m_renderer->Clear(BLACK);
  m_effect->SelectPass("pass_screen");
  m_effect->SetShaderParam("TexScene", m_texRTScene1);
  m_effect->SetShaderParam("TexParticle", m_texRTScene2);

  DrawScreenAlignedBox();
}

APP_MAIN_IMPLEMENTATION(Burning);

Burning::Burning():
m_model(NULL), m_emitter(NULL), m_effect(NULL),
m_paused(false)
{
  
}

Burning::~Burning()
{
  TwTerminate();

  SAFE_DELETE(m_emitter);
}

void Burning::loadAssets()
{
  m_texRTScene1 = m_renderer->CreateTexture(Texture::MIPMAP_DYNAMIC);
  m_texRTScene1->Create(1024, 1024, PIXEL_R8G8B8A8);
  m_rtScrene1 = m_renderer->CreateRenderTarget();
  m_rtScrene1->Create(m_texRTScene1);

  m_texRTScene2 = m_renderer->CreateTexture(Texture::MIPMAP_DYNAMIC);
  m_texRTScene2->Create(1024, 1024, PIXEL_R8G8B8A8);
  m_rtScrene2 = m_renderer->CreateRenderTarget();
  m_rtScrene2->Create(m_texRTScene2);

  // load a texture for model
  m_texOak = Texture::CreateFromFile("OAK.jpg");

  // load a model
  m_model = MeshManager::InstanceRef().LoadObj("model1", "monkey2.obj");

  // load effect
  m_effect = new CGEffect("particle.cgfx");
  m_effect->Create();

  // setup particle parameters
  RayFrame::ParticleParameter* param = m_emitter->GetParameterRef();
  //param->TextureRef = Texture::CreateFromFile("sprites/black_smoke.dds");
  param->TextureRef = Texture::CreateFromFile("sprites/fire_ball6.dds");
  param->TilesX = 1;
  param->TilesY = 1;
  param->Size = 1.0;
  param->ParticleLifeTime = 2.5f;
  param->Color = glm::vec4(1.0, 1.3, 1.3, 1.0);
  param->Count = 20;
  param->RotationRate = glm::vec3(0,0,30);
  float keyX[] = {0.f, 0.2f, 0.3f, 1.f };
  float keyY[] = {0.f, 1.0f, 0.2, 0.f };
  param->AlphaCurv.SetKeys(keyX, keyY, 4, Curve::LINEAR);

  // load gui lib
  TwInit(TW_OPENGL, NULL);
  TwWindowSize((int)GetCamera()->GetViewportSize().x, (int)GetCamera()->GetViewportSize().y);
  TwBar *myBar;
  myBar = TwNewBar("TestBar");
  
  // setup bar parameters
  TwAddVarRW(myBar, "Count", TW_TYPE_INT32, &param->Count, "min=1 max=500 step=1");
  TwAddVarRW(myBar, "ParticleLifeTime", TW_TYPE_FLOAT, &param->ParticleLifeTime, "min=0.1 max=500 step=0.1");
  TwAddVarRW(myBar, "ParticleLifeTimeVar", TW_TYPE_FLOAT, &param->ParticleLifeTimeVar, "min=0 max=3 step=0.1");
  TwAddVarRW(myBar, "Alpha", TW_TYPE_FLOAT, &param->Alpha, "min=0 max=1 step=0.1");
  TwAddVarRW(myBar, "Speed", TW_TYPE_DIR3F, &param->Speed, " label='Move direction' opened=true help='Change the Move direction and speed.' ");
  TwAddVarRW(myBar, "RandomOffsetX", TW_TYPE_FLOAT, &param->RandomOffset[0], "min=0 max=3 step=0.1");
  TwAddVarRW(myBar, "RandomOffsetY", TW_TYPE_FLOAT, &param->RandomOffset[1], "min=0 max=3 step=0.1");
  TwAddVarRW(myBar, "RandomOffsetZ", TW_TYPE_FLOAT, &param->RandomOffset[2], "min=0 max=3 step=0.1");
  TwAddVarRW(myBar, "EmitAngle", TW_TYPE_FLOAT, &param->EmitAngle, "min=0 max=90 step=1");

  
  g_winApp->RegisterWindowsEventCallback(TwEventWin32);

  assert(m_model);
}

void Burning::InitApp()
{
  __super::InitApp();

  m_renderer->GetDefaultFont()->SetFontColor(WHITE);

  m_emitter = new ParticleEmitter;
  loadAssets();
}

bool Burning::OnKey(unsigned key, bool down)
{

  // keyboard event here
  if(!down)
  switch(key)
  {
  case 'c':
  case 'C':
    m_rtScrene1->Download("scene1.bmp");
    m_rtScrene2->Download("scene2.bmp");
    break;
  case 'p':
  case 'P':
    m_paused = !m_paused;
    break;
  }
  if(down)
    TwKeyPressed(key, TW_KMOD_NONE);
  return WindowsApp::OnKey(key, down);
}

void Burning::OnClose()
{

}

void Burning::Update( double timeElapsed )
{
  if(m_emitter && !m_paused)
    m_emitter->Update(timeElapsed);
}

void Burning::OnResize( int width, int height )
{
  __super::OnResize(width, height);

  TwWindowSize(width, height);
}

bool Burning::OnMouseMove( int x, int y, int lastX, int lastY )
{
  //TwMouseMotion(x, y);

  return __super::OnMouseMove(x, y, lastX, lastY);
}

void Burning::OnMouseButton( int x, int y, MouseButton btn, bool down )
{
  //TwMouseButton( down ? TW_MOUSE_PRESSED : TW_MOUSE_RELEASED,
  //  (ETwMouseButtonID) btn );
  return __super::OnMouseButton(x, y, btn, down);
}

void Burning::OnMouseWheel( int x, int y, int speed )
{
  return __super::OnMouseWheel(x, y, speed);
}
